package com.dzsw.thread;

/**
 * 1. wait 方法是 Java 中每个对象都拥有的方法，它继承自 Object 类。
 * 2. wait 方法使当前线程进入等待状态，直到其他线程调用该对象的 notify 方法或 notifyAll 方法。
 * 3. wait 方法必须在同步代码块中使用，否则抛出 InterruptedException 异常。
 *
 */
public class ObjectWaitSample {

    public static void main(String[] args) {
//        wait1();
        wait2();
//        wait3();
    }

    /**
     * 1. 不带超时的 wait 方法，需要被其他线程调用 notify 唤醒后才能继续执行。
     * public final void wait() throws InterruptedException;
     *
     * 调用 wait 方法前，必须持有对象锁。
     * 调用 wait 方法后，立即释放对象锁。
     * 被唤醒后，需要重新竞争对象锁，才能继续执行。
     */
    public static void wait1() {
        Object obj = new Object();
        // t1
        new Thread(() -> {
            synchronized (obj) {
                try {
                    System.out.println("t1 进入等待状态。");
                    obj.wait();
                    System.out.printf("t1 被唤醒后继续执行。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        // t2
        new Thread(() -> {
            synchronized (obj) {
                try {
                    Thread.sleep(5 * 1000);
                    System.out.println("t2 开始唤醒 t1");
                    obj.notify();
                    System.out.println("t2 唤醒 t1 成功！");
                    System.out.println("t2 睡眠 3 秒，不释放锁！");
                    Thread.sleep(3 * 1000);
                    System.out.println("t2 睡眠结束，释放锁！");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        /**
         * 运行结果：
         * t1 进入等待状态。
         * t2 开始唤醒 t1
         * t2 唤醒 t1 成功！
         * t2 睡眠 3 秒，不释放锁！
         * t2 睡眠结束，释放锁！
         * t1 被唤醒后继续执行。
         */
    }

    /**
     * 2. 带超时的 wait 方法。
     * public final native void wait(long timeoutMillis) throws InterruptedException;
     *
     * 超时后，仍需要重新竞争对象锁，再继续执行。
     */
    public static void wait2() {
        Object obj = new Object();
        // t1
        new Thread(() -> {
            synchronized (obj) {
                try {
                    System.out.println("t1 进入等待状态。");
                    obj.wait(5 * 1000);
                    System.out.println("t1 超过等待时间后继续执行。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        // t2
        new Thread(() -> {
            synchronized (obj) {
                try {
                    System.out.println("t2 开始睡眠 5 秒，不释放锁。");
                    Thread.sleep(5 * 1000);
                    System.out.println("t2 睡眠结束，释放锁。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 3. 必须在同步代码块中使用 wait 方法。
     * 抛出异常
     * Exception in thread "main" java.lang.IllegalMonitorStateException: current thread is not owner
     */
    public static void wait3() {
        Object obj = new Object();
        try {
            System.out.println("t1 进入等待状态。");
            obj.wait(5 * 1000);
            System.out.printf("t1 超过等待时间后继续执行。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
